#ifndef _COAP_H
#define _COAP_H

#define COAP_DEBUG

#ifdef COAP_DEBUG
#include <stdio.h>
#define COAP_Debug(format,...)  printf(format"\n",##__VA_ARGS__)
#else
#define COAP_Debug(format,...) 
#endif


#include <stdint.h>
#include <string.h>


#define COAP_PAYLOAD_START 0xff




#define COAP_MSG_CON    0
#define COAP_MSG_NON    1
#define COAP_MSG_ACK    2
#define COAP_MSG_RET    3


#define COAP_CODE_REQUEST      0
#define COAP_CODE_RESPONSE     2
#define COAP_CODE_CLIENT_ERR   4
#define COAP_CODE_SERVER_ERR   5


#define COAP_REQUEST_GET       1
#define COAP_REQUEST_POST      2
#define COAP_REQUEST_PUT       3
#define COAP_REQUEST_DELETE    4
#define COAP_REQUEST_FETCH     5 /* RFC 8132 */
#define COAP_REQUEST_PATCH     6 /* RFC 8132 */
#define COAP_REQUEST_IPATCH    7 /* RFC 8132 */



/* CoAP option types (be sure to update check_critical when adding options */

#define COAP_OPTION_IF_MATCH        1 /* C, opaque, 0-8 B, (none) */
#define COAP_OPTION_URI_HOST        3 /* C, String, 1-255 B, destination address */
#define COAP_OPTION_ETAG            4 /* E, opaque, 1-8 B, (none) */
#define COAP_OPTION_IF_NONE_MATCH   5 /* empty, 0 B, (none) */
#define COAP_OPTION_URI_PORT        7 /* C, uint, 0-2 B, destination port */
#define COAP_OPTION_LOCATION_PATH   8 /* E, String, 0-255 B, - */
#define COAP_OPTION_URI_PATH       11 /* C, String, 0-255 B, (none) */
#define COAP_OPTION_CONTENT_FORMAT 12 /* E, uint, 0-2 B, (none) */
#define COAP_OPTION_CONTENT_TYPE COAP_OPTION_CONTENT_FORMAT
#define COAP_OPTION_MAXAGE         14 /* E, uint, 0--4 B, 60 Seconds */
#define COAP_OPTION_URI_QUERY      15 /* C, String, 1-255 B, (none) */
#define COAP_OPTION_ACCEPT         17 /* C, uint,   0-2 B, (none) */
#define COAP_OPTION_LOCATION_QUERY 20 /* E, String,   0-255 B, (none) */
#define COAP_OPTION_PROXY_URI      35 /* C, String, 1-1034 B, (none) */
#define COAP_OPTION_PROXY_SCHEME   39 /* C, String, 1-255 B, (none) */
#define COAP_OPTION_SIZE1          60 /* E, uint, 0-4 B, (none) */

/* option types from RFC 7641 */

#define COAP_OPTION_OBSERVE         6 /* E, empty/uint, 0 B/0-3 B, (none) */
#define COAP_OPTION_SUBSCRIPTION  COAP_OPTION_OBSERVE

/* selected option types from RFC 7959 */

#define COAP_OPTION_BLOCK2         23 /* C, uint, 0--3 B, (none) */
#define COAP_OPTION_BLOCK1         27 /* C, uint, 0--3 B, (none) */

/* selected option types from RFC 7967 */

#define COAP_OPTION_NORESPONSE    258 /* N, uint, 0--1 B, 0 */

#define COAP_MAX_OPT            65535 /**< the highest option number we know */





typedef struct {
	uint8_t version;
	uint8_t type;
	uint8_t token_size;
	uint8_t code;
	uint16_t id;
}coap_fhdr_t;



typedef struct {
	uint8_t   token_size;
	uint8_t*  token_value;
	uint8_t   option_size;
	uint8_t*  option_data;
}coap_vhdr_t;



typedef struct {
	uint8_t  size;
	uint8_t* data;
	uint16_t max_size;
}coap_variable_t;


typedef struct {
	uint16_t delta;
	uint16_t length;
	uint8_t* data;
}coap_option_t;


typedef struct {
	uint16_t length;
	uint8_t* context;
}coap_payload_t;

#ifdef __cplusplus
extern "C" {
#endif


void attach_variable_part(coap_variable_t* part, uint16_t max_len, uint8_t* data);

/// package
int assemble_package(coap_variable_t* pkg, coap_variable_t* header, coap_variable_t* payload);
int parse_package(coap_variable_t* pkg, coap_fhdr_t* fhdr, coap_variable_t* token, coap_variable_t* option_list, coap_variable_t* payload);

/// header
int assemble_header(coap_variable_t* buf, coap_fhdr_t* fhdr, coap_variable_t* token, coap_variable_t* option_list);


/// option
int assemble_option(uint8_t* pBuf, uint16_t max_len, coap_option_t* opt);
int parse_option(uint8_t* pBuf, uint16_t buf_size, coap_option_t* option);
int append_option(coap_variable_t* buf, coap_option_t* option);
void set_option(coap_option_t* opt, uint16_t delta, uint16_t length, uint8_t* data);
uint16_t get_option_param(uint8_t* buf, uint16_t* pDelta, uint16_t* pLength);


/// token
int set_token(coap_variable_t* token, uint8_t* data, uint8_t length);


void joint_vtcid(coap_variable_t* buf, uint8_t version, uint8_t type, uint8_t code, uint16_t id);
void joint_token(coap_variable_t* buf, uint8_t tkl, uint8_t* token_value);
void joint_option(coap_variable_t* buf, uint16_t delta, uint16_t length, uint8_t* option_value);
void joint_payload(coap_variable_t* buf, uint16_t length, uint8_t* payload_value);

#ifdef __cplusplus
}
#endif


#endif
